package com.example.demo.com.java8.stream;

import java.util.stream.LongStream;
import java.util.stream.Stream;

public class ParallelStreams {

    public static long iterativeSum(long n) {
        long result = 0;
        for (long i = 0; i <= n; i++) {
            result += i;
        }
        return result;
    }

    public static long sequentialSum(long n) {
        return Stream.iterate(1L, i -> i + 1).limit(n).reduce(Long::sum).get();
    }

    /**
     *   iterate 生成的是装箱的对象，必须拆箱成数字才能求和；
     *  我们很难把 iterate 分成多个独立块来并行执行。
     * 第二个问题更有意思一点，因为你必须意识到某些流操作比其他操作更容易并行化。具体来
     * 说， iterate 很难分割成能够独立执行的小块，因为每次应用这个函数都要依赖前一次应用的结
     * 果
     * @param n
     * @return
     */
    public static long parallelSum(long n) {
        return Stream.iterate(1L, i -> i + 1).limit(n).parallel().reduce(Long::sum).get();
    }
    // LongStream.rangeClosed 直接产生原始类型的 long 数字，没有装箱拆箱的开销。
    // LongStream.rangeClosed 会生成数字范围，很容易拆分为独立的小块。例如，范围1~20
    // 可分为1~5、6~10、11~15和16~20。
    public static long rangedSum(long n) {
        return LongStream.rangeClosed(1, n).reduce(Long::sum).getAsLong();
    }

    public static long parallelRangedSum(long n) {
        return LongStream.rangeClosed(1, n).parallel().reduce(Long::sum).getAsLong();
    }


    public static long sideEffectSum(long n) {
        Accumulator accumulator = new Accumulator();
        LongStream.rangeClosed(1, n).forEach(accumulator::add);
        return accumulator.total;
    }
    /**
     * 这是由于多个线程在同时访问累加器，执行 total += value ，而这
     * 一句虽然看似简单，却不是一个原子操作。问题的根源在于， forEach 中调用的方法有副作用，
     * 它会改变多个线程共享的对象的可变状态。要是你想用并行 Stream 又不想引发类似的意外，就
     * 必须避免这种情况
     * @param n
     * @return
     */
    public static long sideEffectParallelSum(long n) {
        Accumulator accumulator = new Accumulator();
        LongStream.rangeClosed(1, n).parallel().forEach(accumulator::add);
        return accumulator.total;
    }

    public static class Accumulator {
        private long total = 0;

        public void add(long value) {
            total += value;
        }
    }
}
